/*
    基于tcp协议的网络计算机，主要解决数据读取在应用层保证完整性问题
*/
#include "tcpserver.hpp"
#include "calculate.hpp"
#include <unistd.h>

void useTips(char *command)
{
    std::cout << "useTips:" << command << " port" << std::endl;
}

using server_t = function<protocol_ns::Response(protocol_ns::Request &)>;

class Server
{
public:
    Server(server_t server) : _server(server)
    {
    }

    void commonServer(shared_ptr<socket_ns::TcpSocket> &communicationsocket, struct sockaddr_in &srcaddr)
    {
        LOG(INFO, "[%s:%d] is linking......\n", inet_ntoa(srcaddr.sin_addr), ntohs(srcaddr.sin_port));
        string packstr = "";
        while (true) // 一直服务当前用户
        {
            // 1、接收来自客户端的报文
            communicationsocket->Recv(packstr); // 每次报文都会累加到str上

            while (true) // 一直处理请求，依次处理一个完整的报文
            {
                // 1.1、解包
                string jsonstr = protocol_ns::decoding(packstr);
                if (jsonstr.empty()) // 读到的数据不包含一个完整的报文
                    break;

                cout << "jsonstr:" << jsonstr << endl;
                // 2、将字符串反序列化json格式数据,并将json格式数据转换成自定义结构数据
                protocol_ns::Request req;
                req.nonSerialized(jsonstr);

                // 3、处理数据
                protocol_ns::Response res = _server(req);

                // 4、将结果转换成json格式再序列化成字符串
                jsonstr.clear();
                res.serialized(jsonstr); // jsonstr是输出型参数

                // 5、添加协议报头
                string tmp = protocol_ns::encoding(jsonstr);

                // 5、返回处理结果
                cout << "packstr:" << tmp << endl;
                communicationsocket->Send(tmp);
            }
        }
    }

private:
    server_t _server; // 回调函数
};

int main(int argc, char *argv[])
{
    if (argc != 2)
        useTips(argv[0]);

    // 0、创建计算器服务(osi中应用层)
    Calculate cal;

    // 1、创建（表示层）
    Server ser(std::bind(&Calculate::excute, &cal, placeholders::_1));

    // 1、创建服务器（会话层）
    unique_ptr<TcpServer_ns::TcpServer> svr = make_unique<TcpServer_ns::TcpServer>(stoi(argv[1]), std::bind(&Server::commonServer, &ser, placeholders::_1, placeholders::_2));

    // 2、启动服务器
    svr->start();

    return 0;
}